﻿using Hopeless.Physical;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UCS.XNA.Utils;

namespace Hopeless.Physical
{
    public class Universe
    {
        public Universe()
        {
        }

        private Hero _hero;
        internal Hero Hero
        {
            get { return _hero; }
        }

        private Sword _heroSword;

        private Terrain _terrain;
        internal Terrain Terrain
        {
            get { return _terrain; }
        }

        private Abyss _abyss;
        internal Abyss Abyss
        {
            get { return _abyss; }
        }

        private List<BloodSpill> _bloodSpills;
        internal List<BloodSpill> BloodSpills
        {
            get { return _bloodSpills; }
        }

        private List<ZombieSpawn> _zombieSpawns;
        internal List<ZombieSpawn> ZombieSpawns
        {
            get { return _zombieSpawns; }
        }

        private Wave _currentWave;
        internal Wave CurrentWave
        {
            get { return _currentWave; }
        }

        private bool _currentWaveFinished = false;
        public bool CurrentWaveFinished
        {
            get { return _currentWaveFinished; }
        }

        private bool _allWavesFinished = false;
        public bool AllWavesFinished
        {
            get { return _allWavesFinished; }
        }

        private Rectangle _availableSpace;
        private IEnumerator<Wave> _waveEnumerator;

        public void Initialize(Rectangle availableSpace)
        {
            _availableSpace = availableSpace;

            _hero = new Hero();
            _heroSword = new Sword();
            _bloodSpills = new List<BloodSpill>();
            _abyss = new Abyss();
            _zombieSpawns = new List<ZombieSpawn>();
            _terrain = new Terrain();
            _waveEnumerator = this.GetWaves().GetEnumerator();
            _waveEnumerator.MoveNext();
            this.StartNextWave();
            _allWavesFinished = false;

            var abyssSpace = new Rectangle(_availableSpace.X, (int)(_availableSpace.Bottom - _availableSpace.Height * 0.3), _availableSpace.Width, (int)(_availableSpace.Height * 0.3));
            _abyss.Initialize(abyssSpace);
            var terrainSpace = new Rectangle(_availableSpace.X, _availableSpace.Y, _availableSpace.Width, (int)(_availableSpace.Height * 0.7));
            _terrain.Initialize(terrainSpace);

            _zombieSpawns = new List<ZombieSpawn>();
            var topSpawn = new ZombieSpawn(5);
            topSpawn.Initialize(new Rectangle(terrainSpace.X, terrainSpace.Y - 50, terrainSpace.Width, 50));
            var leftSpawn = new ZombieSpawn(5);
            leftSpawn.Initialize(new Rectangle(terrainSpace.X - 50, terrainSpace.Y, 50, terrainSpace.Height));
            var rightSpawn = new ZombieSpawn(5);
            rightSpawn.Initialize(new Rectangle(terrainSpace.Right, terrainSpace.Y, 50, terrainSpace.Height));
            _zombieSpawns.Add(topSpawn);
            _zombieSpawns.Add(leftSpawn);
            _zombieSpawns.Add(rightSpawn);

            _hero.Initialize();
            _hero.Position = new Vector2((int)(_availableSpace.X + _availableSpace.Width / 2), (int)(_availableSpace.Y + _availableSpace.Height / 2));
            _hero.Sword = _heroSword;
            _heroSword.Initialize();
        }

        public void Update(GameTime gameTime)
        {
            if (_hero != null)
            {
                _hero.Update(gameTime);
                _heroSword.Update(gameTime);

                if (_hero.IsDead)
                    _hero = null;
            }

            foreach (var zombie in _currentWave.SpawnedZombies)
                zombie.Update(gameTime);

            _abyss.Update(gameTime);

            _currentWave.Update(gameTime);

            _currentWaveFinished = !_currentWave.Zombies.Any() && !_currentWave.SpawnedZombies.Any();
        }

        public void Draw(GameTime gameTime)
        {
            _abyss.Draw(gameTime);
            _terrain.Draw(gameTime);

            foreach (var bloodSpill in _bloodSpills)
                bloodSpill.Draw(gameTime);

            if (_hero != null)
            {
                _heroSword.Draw(gameTime);
                _hero.Draw(gameTime);
            }

            foreach (var zombie in _currentWave.SpawnedZombies)
                zombie.Draw(gameTime);
        }

        public void StartNextWave()
        {
            _currentWave = _waveEnumerator.Current;
            _currentWaveFinished = false;
            if (!_waveEnumerator.MoveNext())
                _allWavesFinished = true;
        }

        private IEnumerable<Wave> GetWaves()
        {
            //yield return new Wave(1, 0, 1);
            //yield return new Wave(2, 1, 1);
            //yield return new Wave(3, 1, 1);
            //yield return new Wave(4, 1, 1);
            //yield return new Wave(5, 1, 1);
            //yield return new Wave(6, 1, 1);
            yield return new Wave(1, 6, 3);
            yield return new Wave(2, 10, 5);
            yield return new Wave(3, 10, 10);
            yield return new Wave(4, 15, 10);
            yield return new Wave(5, 30, 15);
            yield return new Wave(6, 30, 20);
        }
    }
}
